﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using Framework.Common;
using Framework.Common.Attributes;
using Framework.Common.Reflection;
using Framework.Common.Reflection.RunSharpEmit;
using Framework.Serializer;
namespace Framework.Sample
{
    [OrderedDesc("6)    simple orm mapping (Emit)")]
    class Test6 : ITest
    {
        public void Run()
        {
            Console.WriteLine(@"simple orm mapping : DataTable or DbReader To Entity");
            //prepare data
            DataTable dt = new DataTable();
            dt.Columns.Add("Name");
            dt.Columns.Add("Age", typeof(int));
            dt.Columns.Add("Id", typeof(int));
            dt.Rows.Add(new object[] { "name11", 88, 11 });
            dt.Rows.Add(new object[] { "name21", 88, 21 });
            dt.Rows.Add(new object[] { "name31", 88, 31 });
            dt.Rows.Add(new object[] { "name41", 88, 41 });

            //get
            var list = ConvertToList1<Person>(dt);
            Console.WriteLine(list.Count);
            ConvertToList2<Person>(dt);
        }

        private List<T> ConvertToList1<T>(DataTable dt) where T : new()
        {
            DynamicMethodGen dmg = DynamicMethodGen.Static(typeof(T)).Method(typeof(T)).Parameter(typeof(DataRow), "p0");
            CodeGen cg = dmg.GetCode();
            var pis = typeof(T).GetProperties();
            if (pis.Length > 0)
            {
                var model = cg.Local(Exp.New(typeof(T)));
                foreach (var pi in pis)
                {
                    if (DynamicMethodCreate.ObjectConvertMethodDict.ContainsKey(pi.PropertyType))
                    {
                        string convertMethodName = DynamicMethodCreate.ObjectConvertMethodDict[pi.PropertyType];
                        Operand orignal = cg.Local(cg.Arg("p0")[pi.Name]);
                        cg.If(orignal.NE(null));
                        Operand value = Static.Invoke(typeof(TypeConvertHelper), convertMethodName, cg.Arg("p0")[pi.Name]);
                        cg.Assign(model.Property(pi.Name), value);
                        cg.End();
                    }
                }
                cg.Return(model);
            }
            else
            {
                throw new Exception(typeof(T).Name + " not contains any property");
            }
            DynamicMethod dm = dmg.GetCompletedDynamicMethod(true);
            Func<DataRow, T> func = (Func<DataRow, T>)dm.CreateDelegate(typeof(Func<DataRow, T>));


            List<T> list = new List<T>();
            foreach (DataRow dr in dt.Rows)
            {
                list.Add(func(dr));
            }
            return list;
        }

        private List<T> ConvertToList2<T>(DataTable dt) where T : new()
        {
            //Func<DataTable, List<T>> func = DynamicMethodCreate.CreateFunc<DataTable, List<T>>(cg =>
            //{

            //}, "ConvertToList2" + typeof(T).Name);

            DynamicMethodCreate.TestFunc<DataTable, List<T>>(cg =>
                {
                    var list = cg.Local(Exp.New(typeof(List<T>)));
                    Operand table = cg.Local(cg.Arg("p0"));
                    var row = cg.ForEach(typeof(DataRow), table.Property("Rows"));
                    {
                        var t = cg.Local(Exp.New(typeof(T)));
                        var pis = typeof(T).GetProperties();
                        foreach (var pi in pis)
                        {
                            if (DynamicMethodCreate.ObjectConvertMethodDict.ContainsKey(pi.PropertyType))
                            {
                                string convertMethodName = DynamicMethodCreate.ObjectConvertMethodDict[pi.PropertyType];
                                Operand orignal = cg.Local(row[pi.Name]);
                                cg.If(orignal.NE(null));
                                Operand value = Static.Invoke(typeof(TypeConvertHelper), convertMethodName, orignal);
                                cg.Assign(t.Property(pi.Name), value);
                                cg.End();
                            }
                        }
                        cg.Invoke(list, "Add", t);
                        cg.WriteLine(1);
                    }
                    cg.End();
                    cg.Return(list);
                });

            return null;
        }
    }
}
